home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 October: Mac OS SDK / Dev.CD Oct 96 SDK / Dev.CD Oct 96 SDK2.toast / Development Kits (Disc 2) / OpenDoc Development Framework / ODFDev / ODF / Found / FWString / Sources / SLStrRep.cpp < prev    next >
Encoding:
Text File  |  1996-08-16  |  42.5 KB  |  1,481 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                SLStrRep.cpp
  4. //    Release Version:    $ ODF 1 $
  5. //
  6. //    Copyright:    (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  7. //
  8. //========================================================================================
  9.  
  10. #include "FWFound.hpp"
  11.  
  12. #ifndef PRSTRREP_H
  13. #include "PRStrRep.h"
  14. #endif
  15.  
  16. #ifndef SLPRIDEB_H
  17. #include "SLPriDeb.h"
  18. #endif
  19.  
  20. #ifndef SLPRIMEM_H
  21. #include "SLPriMem.h"
  22. #endif
  23.  
  24. // ----- Foundation Includes -----
  25.  
  26. #ifndef FWPRIDEB_H
  27. #include "FWPriDeb.h"
  28. #endif
  29.  
  30. #ifdef FW_BUILD_MAC
  31. #include <OSA.h>
  32. #endif
  33.  
  34. #ifdef FW_BUILD_MAC
  35. #include <Script.h>
  36. #endif
  37.  
  38. #ifndef _ERRORDEF_
  39. #include "ErrorDef.xh"
  40. #endif
  41.  
  42. #ifdef FW_BUILD_MAC
  43. #include <TextUtils.h>
  44. #endif
  45.  
  46. #ifdef FW_BUILD_MAC
  47. #include <fp.h>
  48. #endif
  49.  
  50. #ifdef FW_BUILD_MAC
  51. #pragma segment Strings
  52. #endif
  53.  
  54. //========================================================================================
  55. //    gEmptyStringRep
  56. //========================================================================================
  57.  
  58. static FW_Locale gEmptyStringData = 
  59. {
  60. #ifdef FW_BUILD_MAC
  61.     smRoman,        // fScriptCode
  62.     langEnglish        // fLangCode
  63. #endif
  64. #ifdef FW_BUILD_WIN
  65.     0,
  66.     0
  67. #endif
  68. };
  69.  
  70. static FW_SPrivStringRep gEmptyStringRep = 
  71. {
  72.     {    // ODIText fText;
  73.         kODTraditionalMacText,            // format
  74.         {
  75.             sizeof(gEmptyStringData),    // _maximum
  76.             sizeof(gEmptyStringData),    // _length
  77.             (unsigned char*) &gEmptyStringData            // _buffer
  78.         }
  79.     },
  80.     {    // FW_ODITextParams    fParams;
  81.         (char*) &gEmptyStringData+sizeof(gEmptyStringData),    // fTextStart
  82.         0,                                // fTextByteLength
  83.         0                                // fTextByteCapacity
  84.     },
  85.     100,                                // fRefCount
  86.     true,                                // fUsingStaticBuffer
  87.     false                                // fLocked
  88. };
  89.  
  90. //========================================================================================
  91. //    FW_SPrivStringRep Functions
  92. //========================================================================================
  93.  
  94. //----------------------------------------------------------------------------------------
  95. //    FW_Check
  96. //----------------------------------------------------------------------------------------
  97.  
  98.  
  99. #ifdef FW_DEBUG
  100.     static void FW_Check(FW_HString self, long minRefCount)
  101.     {
  102.         // No need for FW_ERR_TRY block
  103.         FW_PlatformError error;
  104.         FW_PRIV_ASSERT(self);
  105.         FW_PRIV_ASSERT(self->fRefCount>=minRefCount);
  106.         FW_PRIV_ASSERT(0 <= self->fText.text._length);
  107.         FW_PRIV_ASSERT(self->fText.text._length <= self->fText.text._maximum);
  108.         FW_PRIV_ASSERT(self->fText.text._buffer!=0);
  109.  
  110.         FW_ODITextParams params;
  111.         FW_TextParams_GetParams(&self->fText, ¶ms, &error);
  112.         FW_PRIV_ASSERT(error == 0);
  113.         FW_PRIV_ASSERT(self->fParams.fTextStart == params.fTextStart);
  114.         FW_PRIV_ASSERT(self->fParams.fTextByteLength == params.fTextByteLength);
  115.         FW_PRIV_ASSERT(self->fParams.fTextByteCapacity == params.fTextByteCapacity);
  116.         FW_PRIV_ASSERT(self->fParams.fTextByteLength <= self->fParams.fTextByteCapacity);
  117.     }
  118.     #define FW_CHECK(self) FW_Check(self, 1);
  119. #else
  120.     #define FW_CHECK(self)
  121. #endif
  122.  
  123. #ifdef FW_DEBUG
  124. #define CHECK_ERROR if (*error) { Debugger(); return 0; } else 0
  125. #else
  126. #define CHECK_ERROR if (*error) { return 0; } else 0
  127. #endif
  128.  
  129. //----------------------------------------------------------------------------------------
  130. //    StringRep_Clone
  131. //----------------------------------------------------------------------------------------
  132. // Conditionally creates a copy.  If the reference count of the
  133. // self is exactly one, or if self is locked, then self is simply returned, unchanged.
  134. // If the reference count of self is greater than one, then 
  135. // its contents are cloned, and self's reference count is decremented.
  136. // The reference count of the copy is set to 1.
  137. // Note that this function conserves the total reference count.
  138.  
  139. static FW_HString StringRep_Clone(FW_HString self, FW_PlatformError *error);
  140.  
  141. static FW_HString StringRep_Clone(FW_HString self, FW_PlatformError *error)
  142. {
  143.     *error = 0;
  144.     FW_CHECK(self);
  145.     
  146.     FW_PRIV_ASSERT(self->fRefCount>=1);
  147.     FW_HString clone = self;
  148.     if ((!self->fLocked) && (self->fRefCount > 1))
  149.     {
  150.         clone = (FW_SPrivStringRep*) FW_PrimitiveAllocateBlock(sizeof(FW_SPrivStringRep));
  151.         if (clone == NULL)
  152.         {
  153.             *error = kODErrOutOfMemory;
  154.             return 0;
  155.         }
  156.         *clone = *self;
  157.         clone->fRefCount = 0;
  158.         clone->fText.text._buffer = (unsigned char*) 
  159.                             FW_PrimitiveAllocateBlock(self->fText.text._maximum);
  160.         if (clone->fText.text._buffer == NULL)
  161.         {
  162.             *error = kODErrOutOfMemory;
  163.             return 0;
  164.         }
  165.         clone->fText.text._maximum = self->fText.text._maximum;
  166.         clone->fUsingStaticBuffer = false;
  167.         clone->fLocked = false;
  168.         ::FW_PrimitiveCopyMemory(self->fText.text._buffer, 
  169.                             clone->fText.text._buffer, 
  170.                             self->fText.text._length);
  171.         ::FW_TextParams_GetParams(&clone->fText, &clone->fParams, error);
  172.         CHECK_ERROR;
  173.         ::FW_PrivString_Acquire(clone);
  174.         ::FW_PrivString_Release(self);
  175.     }
  176.  
  177.     FW_CHECK(clone);
  178.  
  179.     return clone;
  180. }
  181.  
  182. //----------------------------------------------------------------------------------------
  183. //    FW_PrivString_UseStaticBuffer
  184. //----------------------------------------------------------------------------------------
  185.  
  186. FW_HString FW_PrivString_NewRepWithStaticBuffer(unsigned char* buffer,
  187.                                     FW_ByteCount bufferLen)
  188. {
  189.     FW_HString rep = (FW_SPrivStringRep*) 
  190.                             FW_PrimitiveAllocateBlock(sizeof(FW_SPrivStringRep));
  191.     if (rep != NULL)
  192.     {
  193.         FW_PRIV_ASSERT(bufferLen > sizeof(FW_Locale));
  194.         FW_Locale* locale = (FW_Locale*) buffer;
  195.         *locale = gEmptyStringData;
  196.         
  197.         rep->fText.format = kODTraditionalMacText;
  198.         rep->fText.text._buffer = buffer;
  199.         rep->fText.text._maximum = bufferLen;
  200.         rep->fText.text._length = sizeof(gEmptyStringData);
  201.         
  202.         rep->fParams.fTextStart = (char*) buffer + sizeof(gEmptyStringData);
  203.         rep->fParams.fTextByteLength = 0;
  204.         rep->fParams.fTextByteCapacity = bufferLen - sizeof(gEmptyStringData);
  205.         
  206.         rep->fRefCount = 0;
  207.         rep->fUsingStaticBuffer = true;
  208.         rep->fLocked = false;
  209.     }
  210.     
  211.     return rep;
  212. }
  213.  
  214. //----------------------------------------------------------------------------------------
  215. //    FW_PrivString_ReleaseStaticBuffer
  216. //----------------------------------------------------------------------------------------
  217.  
  218. void FW_PrivString_ReleaseStaticBuffer(FW_HString self, FW_PlatformError* error)
  219. {
  220.     // This function should only be called from the destructor of bounded string
  221.     // classes.  When a bounded string class is being destroyed, the static buffer
  222.     // can no longer be used.  There are several cases that must be considered:
  223.     //
  224.     // 1) The StringRep is no longer using the static buffer because some
  225.     // operation caused the buffer to be reallocated (e.g. an append operation
  226.     // caused the string to grow beyond the capacity of the buffer).  In this
  227.     // case, the buffer has already been released, and nothing needs to be done.
  228.     // 
  229.     // 2) The StringRep is still using the static buffer, but the reference
  230.     // count is 1.  In that case, the last reference is about to be released
  231.     // and the whole rep will be blown away.  We don't need to save the contents
  232.     // of the buffer, and we especially do not want to clear the fUsingStaticBuffer
  233.     // flag, because that would cause FW_PrivString_Release to erroneously attempt
  234.     // to delete the buffer, which would likely corrupt the heap.  This means
  235.     // the correct thing is again to do nothing.
  236.     //
  237.     // 3) The stringRep is still using the static buffer, but the reference
  238.     // count is greater than 1.  In that case, a dynamic buffer must be allocated
  239.     // for the contents of the string.  We can safely mark the string as no longer
  240.     // using the static buffer (i.e. set fUsingStaticBuffer to false), since
  241.     // FW_PrivString_Release will only decrement the reference count and not
  242.     // delete the rep.
  243.  
  244.     *error = 0;
  245.     FW_CHECK(self);
  246.  
  247.     if (self->fRefCount>1 && self->fUsingStaticBuffer)
  248.     {
  249.         unsigned char* newBuffer = (unsigned char*) 
  250.                             FW_PrimitiveAllocateBlock(self->fText.text._maximum);
  251.         if (newBuffer == NULL)
  252.         {
  253.             *error = kODErrOutOfMemory;
  254.             return;
  255.         }
  256.         ::FW_PrimitiveCopyMemory(self->fText.text._buffer, 
  257.                             newBuffer, 
  258.                             self->fText.text._length);
  259.         self->fText.text._buffer = newBuffer;
  260.         self->fUsingStaticBuffer = false;
  261.         ::FW_TextParams_GetParams(&self->fText, &self->fParams, error);
  262.     }
  263. }
  264.  
  265. //----------------------------------------------------------------------------------------
  266. //    FW_PrivString_LockString
  267. //----------------------------------------------------------------------------------------
  268.  
  269. FW_HString FW_PrivString_LockString(FW_HString self, FW_PlatformError* error)
  270. {
  271.     FW_HString rep = self;
  272.     if (!rep->fLocked)
  273.     {
  274.         rep = ::StringRep_Clone(rep, error);
  275.         if (*error != 0)
  276.             return 0;
  277.         rep->fLocked = true;
  278.         rep->fRefCount = 0;
  279.     }
  280.     return rep;
  281. }
  282.  
  283. //----------------------------------------------------------------------------------------
  284. //    FW_PrivString_AcquireEmptyString
  285. //----------------------------------------------------------------------------------------
  286.  
  287. FW_HString FW_PrivString_AcquireEmptyString()
  288. {
  289.     FW_HString rep = &gEmptyStringRep;
  290.     ::FW_PrivString_Acquire(rep);
  291.     return rep;
  292. }
  293.  
  294. //----------------------------------------------------------------------------------------
  295. //    FW_PrivString_AcquireEmptyStringWithLocale
  296. //----------------------------------------------------------------------------------------
  297.  
  298. FW_HString FW_PrivString_AcquireEmptyStringWithLocale(FW_Locale locale, FW_PlatformError* error)
  299. {
  300.     FW_HString rep = &gEmptyStringRep;
  301.     ::FW_PrivString_Acquire(rep);
  302.     rep = ::StringRep_Clone(rep, error);
  303.     if (*error != 0)
  304.         return 0;
  305.     ::FW_TextParams_SetLocale(&rep->fText, locale, &rep->fParams, error);
  306.     if (*error != 0)
  307.         return 0;
  308. #ifdef FW_DEBUG
  309.     ::FW_Check(rep, 0);
  310. #endif
  311.     return rep;
  312. }
  313.  
  314. //----------------------------------------------------------------------------------------
  315. //    FW_PrivString_Acquire
  316. //----------------------------------------------------------------------------------------
  317.  
  318. void    FW_PrivString_Acquire(FW_HString self)
  319. {
  320. #ifdef FW_DEBUG
  321.     ::FW_Check(self, 0);
  322. #endif
  323.     ++self->fRefCount;
  324. }
  325.  
  326. //----------------------------------------------------------------------------------------
  327. //    FW_PrivString_Release
  328. //----------------------------------------------------------------------------------------
  329.  
  330. void    FW_PrivString_Release(FW_HString self)
  331. {
  332.     FW_CHECK(self);
  333.     if(--self->fRefCount == 0)
  334.     {
  335.         if (self->fLocked)
  336.         {
  337.             self->fLocked = false;
  338.             self->fRefCount = 1;
  339.         }
  340.         else
  341.         {
  342.             if (!self->fUsingStaticBuffer)
  343.                 FW_PrimitiveFreeBlock(self->fText.text._buffer);
  344.             FW_PrimitiveFreeBlock(self);
  345.         }
  346.     }
  347. }
  348.  
  349. //----------------------------------------------------------------------------------------
  350. //    FW_PrivString_GetByteLength
  351. //----------------------------------------------------------------------------------------
  352.  
  353. FW_ByteCount    FW_PrivString_GetByteLength(FW_HString self)
  354. {
  355.     FW_CHECK(self);
  356.     return self->fParams.fTextByteLength;
  357. }
  358.  
  359. //----------------------------------------------------------------------------------------
  360. //    FW_PrivString_GetCapacity
  361. //----------------------------------------------------------------------------------------
  362.  
  363. FW_ByteCount  FW_PrivString_GetCapacity(FW_HString self)
  364. {
  365.     FW_CHECK(self);
  366.     return self->fParams.fTextByteCapacity;
  367. }
  368.  
  369. //----------------------------------------------------------------------------------------
  370. //    FW_PrivString_GetCharacterLength
  371. //----------------------------------------------------------------------------------------
  372.  
  373. FW_CharacterCount    FW_PrivString_GetCharacterLength(FW_HString self, FW_PlatformError* error)
  374. {
  375.     FW_CHECK(self);
  376.     FW_CharacterCount result = self->fParams.fTextByteLength;// assume singlebyte locale
  377.     if (!::FW_LocaleIsSingleByte(self->fParams.fTextLocale))
  378.     {
  379.         FW_BytePosition knownStart = 0;
  380.         FW_BytePosition position = 0;
  381.         result = 0;
  382.         while (position < self->fParams.fTextByteLength)
  383.         {
  384.             FW_Boolean isStart = ::FW_TextParams_IsCharacterStart(&self->fText, knownStart, position, error);
  385.             if (*error)
  386.                 return 0;
  387.             if (isStart)
  388.             {
  389.                 knownStart = position;
  390.                 result++;
  391.             }
  392.             position++;
  393.         }
  394.     }
  395.     return result;
  396. }
  397.  
  398. //----------------------------------------------------------------------------------------
  399. //    FW_PrivString_RevealODIText
  400. //----------------------------------------------------------------------------------------
  401.  
  402. ODIText*    FW_PrivString_RevealODIText(FW_HString self)
  403. {
  404.     FW_CHECK(self);
  405.     return &self->fText;
  406. }
  407.  
  408. //----------------------------------------------------------------------------------------
  409. //    FW_PrivString_RevealBuffer
  410. //----------------------------------------------------------------------------------------
  411.  
  412. const char*    FW_PrivString_RevealBuffer(FW_HString self)
  413. {
  414.     FW_CHECK(self);
  415.     return self->fParams.fTextStart;
  416. }
  417.  
  418. //----------------------------------------------------------------------------------------
  419. //    FW_PrivString_GetLocale
  420. //----------------------------------------------------------------------------------------
  421.  
  422. void FW_PrivString_GetLocale(FW_HString self, FW_Locale* locale)
  423. {
  424.     FW_CHECK(self);
  425.     *locale = self->fParams.fTextLocale;
  426. }
  427.  
  428. //----------------------------------------------------------------------------------------
  429. //    FW_PrivString_Retrieve
  430. //----------------------------------------------------------------------------------------
  431.  
  432. void FW_PrivString_Retrieve(FW_HString self, 
  433.             char* destination, 
  434.             FW_ByteCount numberBytes, 
  435.             FW_BytePosition position)
  436.  
  437. {
  438.     FW_CHECK(self);
  439.     ::FW_PrimitiveCopyMemory(self->fParams.fTextStart+position, destination, numberBytes);
  440. }
  441.  
  442. //----------------------------------------------------------------------------------------
  443. //    FW_PrivString_Delete
  444. //----------------------------------------------------------------------------------------
  445.  
  446. FW_HString  FW_PrivString_Delete(FW_HString self, 
  447.                                 FW_ByteCount numberBytes, 
  448.                                 FW_BytePosition position, 
  449.                                 FW_PlatformError* error)
  450. {
  451.     FW_HString rep = ::StringRep_Clone(self, error);
  452.     if (*error)
  453.         return 0;
  454.  
  455.     ::FW_PrimitiveCopyMemory(rep->fParams.fTextStart+position+numberBytes, 
  456.                             rep->fParams.fTextStart+position, 
  457.                             rep->fParams.fTextByteLength-position-numberBytes);
  458.  
  459.     ::FW_TextParams_SetLength(&rep->fText, 
  460.                             rep->fParams.fTextByteLength-numberBytes, 
  461.                             &rep->fParams, error);
  462.     if (*error)
  463.         return 0;
  464.  
  465.     return rep;
  466. }
  467.  
  468. //----------------------------------------------------------------------------------------
  469. //    FW_PrivString_Truncate
  470. //----------------------------------------------------------------------------------------
  471.  
  472. FW_HString  FW_PrivString_Truncate(FW_HString self, 
  473.                                 FW_BytePosition position, 
  474.                                 FW_PlatformError* error)
  475. {
  476.     FW_HString rep = ::StringRep_Clone(self, error);
  477.     if (*error)
  478.         return 0;
  479.  
  480.     FW_PRIV_ASSERT(position>=0);
  481.     FW_PRIV_ASSERT(position<=rep->fParams.fTextByteLength);
  482.     
  483.     ::FW_TextParams_SetLength(&rep->fText, position, &rep->fParams, error);
  484.     if (*error)
  485.         return 0;
  486.  
  487.     return rep;
  488. }
  489.  
  490. //----------------------------------------------------------------------------------------
  491. //    FW_PrivString_InsertBytes
  492. //----------------------------------------------------------------------------------------
  493.  
  494. FW_HString FW_PrivString_InsertBytes(FW_HString self, 
  495.                                 const char* bytes, 
  496.                                 FW_ByteCount numberBytes,  
  497.                                 FW_BytePosition position, 
  498.                                 FW_PlatformError* error)
  499. {
  500.     FW_HString rep = ::StringRep_Clone(self, error);
  501.     CHECK_ERROR;
  502.  
  503.     FW_PRIV_ASSERT(bytes);
  504.     FW_PRIV_ASSERT(numberBytes>=0);
  505.     FW_PRIV_ASSERT(position>=0);
  506.     FW_PRIV_ASSERT(position<=rep->fParams.fTextByteLength);
  507.  
  508.     // ensure string will have sufficient capacity
  509.     ::FW_TextParams_SetCapacity(&rep->fText, 
  510.                             rep->fParams.fTextByteLength+numberBytes, 
  511.                             !rep->fUsingStaticBuffer,
  512.                             &rep->fParams, error);
  513.     CHECK_ERROR;
  514.     FW_PRIV_ASSERT(rep->fParams.fTextByteLength+numberBytes 
  515.                     <= rep->fParams.fTextByteCapacity);
  516.  
  517.     // move end of string to new position and make room for insertion
  518.     ::FW_PrimitiveCopyMemory(rep->fParams.fTextStart+position, 
  519.                             rep->fParams.fTextStart+position+numberBytes, 
  520.                             rep->fParams.fTextByteLength-position);
  521.  
  522.     // insert bytes into position in rep
  523.     ::FW_PrimitiveCopyMemory(bytes, 
  524.                             rep->fParams.fTextStart+position, 
  525.                             numberBytes);
  526.  
  527.     // update for the new length
  528.     ::FW_TextParams_SetLength(&rep->fText, 
  529.                             rep->fParams.fTextByteLength+numberBytes, 
  530.                             &rep->fParams, error);
  531.     CHECK_ERROR;
  532.  
  533.     return rep;
  534. }
  535.  
  536. //----------------------------------------------------------------------------------------
  537. //    FW_PrivString_InsertODIText
  538. //----------------------------------------------------------------------------------------
  539.  
  540. FW_HString FW_PrivString_InsertODIText(FW_HString self, 
  541.                                     ODIText* text, 
  542.                                     FW_BytePosition position, 
  543.                                     FW_PlatformError* error)
  544. {
  545.     // No need for FW_ERR_TRY block
  546.     FW_ODITextParams params;
  547.     ::FW_TextParams_GetParams(text, ¶ms, error);
  548.     if (*error)
  549.         return 0;
  550.  
  551.     FW_HString result = ::FW_PrivString_InsertBytes(self, 
  552.                                         params.fTextStart, 
  553.                                         params.fTextByteLength, 
  554.                                         position,
  555.                                         error);
  556.     if (*error)
  557.         return 0;
  558.     return result;
  559. }
  560.  
  561. //----------------------------------------------------------------------------------------
  562. //    FW_PrivString_InsertStringRep
  563. //----------------------------------------------------------------------------------------
  564.  
  565. FW_HString FW_PrivString_InsertStringRep(FW_HString self, 
  566.                                         FW_HString other, 
  567.                                         FW_BytePosition position, 
  568.                                         FW_PlatformError* error)
  569. {
  570.     // No need for FW_ERR_TRY block
  571.     FW_CHECK(other);
  572.     FW_HString result = ::FW_PrivString_InsertBytes(self, 
  573.                                         other->fParams.fTextStart, 
  574.                                         other->fParams.fTextByteLength, 
  575.                                         position,
  576.                                         error);
  577.     if (*error)
  578.         return 0;
  579.     return result;
  580. }
  581.  
  582. //----------------------------------------------------------------------------------------
  583. //    FW_PrivString_ReplaceAllBytes
  584. //----------------------------------------------------------------------------------------
  585.  
  586. FW_HString FW_PrivString_ReplaceAllBytes(FW_HString self,
  587.                                         const char* bytes, 
  588.                                         FW_ByteCount numberBytes, 
  589.                                         FW_PlatformError* error)
  590. {
  591.     FW_HString rep = ::StringRep_Clone(self, error);
  592.     if (*error)
  593.         return 0;
  594.  
  595.     // ensure string will have sufficient capacity
  596.     ::FW_TextParams_SetCapacity(&rep->fText,
  597.                                 numberBytes, 
  598.                                 !rep->fUsingStaticBuffer,
  599.                                 &rep->fParams, 
  600.                                 error);
  601.     if (*error)
  602.         return 0;
  603.  
  604.     // Copy bytes into rep
  605.     ::FW_PrimitiveCopyMemory(bytes, rep->fParams.fTextStart, numberBytes);
  606.  
  607.     // update for the new length
  608.     ::FW_TextParams_SetLength(&rep->fText, numberBytes, &rep->fParams, error);
  609.     if (*error)
  610.         return 0;
  611.  
  612.     return rep;
  613. }
  614.  
  615. //----------------------------------------------------------------------------------------
  616. //    FW_PrivString_ReplaceAllODIText
  617. //----------------------------------------------------------------------------------------
  618.  
  619. FW_HString FW_PrivString_ReplaceAllODIText(FW_HString self, 
  620.                                         ODIText* text, 
  621.                                         FW_PlatformError* error)
  622. {
  623.     // No need for FW_ERR_TRY block
  624.     FW_HString result;
  625.     
  626.     FW_ODITextParams params;
  627.     ::FW_TextParams_GetParams(text, ¶ms, error);
  628.     if (*error)
  629.         return 0;
  630.  
  631.     result = ::FW_PrivString_ReplaceAllBytes(self, 
  632.                                         params.fTextStart, 
  633.                                         params.fTextByteLength,
  634.                                         error);
  635.     if (*error)
  636.         return 0;
  637.     
  638.     return result;
  639. }
  640.  
  641. //----------------------------------------------------------------------------------------
  642. //    FW_PrivString_ReplaceAllStringRep
  643. //----------------------------------------------------------------------------------------
  644.  
  645. FW_HString FW_PrivString_ReplaceAllStringRep(FW_HString self, 
  646.                                         FW_HString other, 
  647.                                         FW_PlatformError* error)
  648. {
  649.     // No need for FW_ERR_TRY block
  650.     FW_HString result = self;
  651.     if (self != other)
  652.     {
  653.         if (self->fLocked)
  654.         {
  655.             result = ::FW_PrivString_ReplaceAllBytes(self, 
  656.                                                 other->fParams.fTextStart, 
  657.                                                 other->fParams.fTextByteLength,
  658.                                                 error);
  659.             if (*error)
  660.                 return 0;
  661.         }
  662.         else
  663.         {
  664.             ::FW_PrivString_Acquire(other);
  665.             ::FW_PrivString_Release(self);
  666.             result = other;
  667.         }
  668.     }
  669.     return result;
  670. }
  671.  
  672. //----------------------------------------------------------------------------------------
  673. //    FW_PrivString_AppendBytes
  674. //----------------------------------------------------------------------------------------
  675.  
  676. FW_HString FW_PrivString_AppendBytes(FW_HString self,
  677.                                     const char* bytes, 
  678.                                     FW_ByteCount numberBytes, 
  679.                                     FW_PlatformError* error)
  680. {
  681.     // No need for FW_ERR_TRY block
  682.     FW_HString result = ::FW_PrivString_InsertBytes(self, 
  683.                                                 bytes, 
  684.                                                 numberBytes, 
  685.                                                 self->fParams.fTextByteLength,
  686.                                                 error);
  687.     CHECK_ERROR;
  688.     return result;
  689. }
  690.  
  691. //----------------------------------------------------------------------------------------
  692. //    FW_PrivString_AppendODIText
  693. //----------------------------------------------------------------------------------------
  694.  
  695. FW_HString FW_PrivString_AppendODIText(FW_HString self, 
  696.                                     ODIText* text, 
  697.                                     FW_PlatformError* error)
  698. {
  699.     // No need for FW_ERR_TRY block
  700.     FW_HString result = ::FW_PrivString_InsertODIText(self, 
  701.                                                     text, 
  702.                                                     self->fParams.fTextByteLength, 
  703.                                                     error);
  704.     CHECK_ERROR;
  705.     return result;
  706. }
  707.  
  708. //----------------------------------------------------------------------------------------
  709. //    FW_PrivString_AppendStringRep
  710. //----------------------------------------------------------------------------------------
  711.  
  712. FW_HString FW_PrivString_AppendStringRep(FW_HString self, 
  713.                                         FW_HString other, 
  714.                                         FW_PlatformError* error)
  715. {
  716.     // No need for FW_ERR_TRY block
  717.     FW_HString result = ::FW_PrivString_InsertStringRep(self, 
  718.                                         other, 
  719.                                         self->fParams.fTextByteLength, 
  720.                                         error);
  721.     if (*error)
  722.         return 0;
  723.     return result;
  724. }
  725.  
  726. //----------------------------------------------------------------------------------------
  727. //    FW_PrivString_PrependBytes
  728. //----------------------------------------------------------------------------------------
  729.  
  730. FW_HString FW_PrivString_PrependBytes(FW_HString self,
  731.                                     const char* bytes, 
  732.                                     FW_ByteCount numberBytes, 
  733.                                     FW_PlatformError* error)
  734. {
  735.     // No need for FW_ERR_TRY block
  736.     FW_HString result = ::FW_PrivString_InsertBytes(self, bytes, numberBytes, 0, error);
  737.     if (*error)
  738.         return 0;
  739.     return result;
  740. }
  741.  
  742. //----------------------------------------------------------------------------------------
  743. //    FW_PrivString_PrependODIText
  744. //----------------------------------------------------------------------------------------
  745.  
  746. FW_HString FW_PrivString_PrependODIText(FW_HString self, 
  747.                                         ODIText* text, 
  748.                                         FW_PlatformError* error)
  749. {
  750.     // No need for FW_ERR_TRY block
  751.     FW_HString result = ::FW_PrivString_InsertODIText(self, text, 0, error);
  752.     if (*error)
  753.         return 0;
  754.     return result;
  755. }
  756.  
  757. //----------------------------------------------------------------------------------------
  758. //    FW_PrivString_PrependStringRep
  759. //----------------------------------------------------------------------------------------
  760.  
  761. FW_HString FW_PrivString_PrependStringRep(FW_HString self, 
  762.                                         FW_HString other, 
  763.                                         FW_PlatformError* error)
  764. {
  765.     // No need for FW_ERR_TRY block
  766.     FW_HString result = ::FW_PrivString_InsertStringRep(self, other, 0, error);
  767.     if (*error)
  768.         return 0;
  769.     return result;
  770. }
  771.  
  772. //----------------------------------------------------------------------------------------
  773. //    FW_PrivString_ExportCString
  774. //----------------------------------------------------------------------------------------
  775.  
  776. void FW_PrivString_ExportCString(FW_HString self, char* buffer)
  777. {
  778.     const char nul = 0;
  779.     ::FW_PrivString_Retrieve(self, buffer, self->fParams.fTextByteLength, 0);
  780.     buffer[self->fParams.fTextByteLength] = nul;
  781. }
  782.  
  783. //----------------------------------------------------------------------------------------
  784. //    FW_PrivString_ExportPascalString
  785. //----------------------------------------------------------------------------------------
  786.  
  787. void FW_PrivString_ExportPascalString(FW_HString self, FW_PascalChar* buffer)
  788. {
  789.     ::FW_PrivString_Retrieve(self, (char*)buffer+1, self->fParams.fTextByteLength, 0);
  790.     buffer[0] = FW_PascalChar(self->fParams.fTextByteLength);
  791. }
  792.  
  793. //----------------------------------------------------------------------------------------
  794. //    FW_PrivString_ToUpper
  795. //----------------------------------------------------------------------------------------
  796.  
  797. FW_HString FW_PrivString_ToUpper(FW_HString self, FW_PlatformError* error)
  798. {
  799.     FW_HString rep = ::StringRep_Clone(self, error);
  800.     if (*error)
  801.         return 0;
  802. #ifdef FW_BUILD_MAC
  803.     ::UppercaseText(rep->fParams.fTextStart, 
  804.                     rep->fParams.fTextByteLength, 
  805.                     rep->fParams.fTextLocale.fScriptCode);
  806.     *error = ::ResError();
  807.     if (*error)
  808.         return 0;
  809. #elif defined FW_BUILD_WIN
  810.     //??? Need an international implementation for windows
  811.     for (int i=0; i<rep->fParams.fTextByteLength; i++)
  812.         rep->fParams.fTextStart[i] = toupper(rep->fParams.fTextStart[i]);
  813. #endif
  814.     return rep;
  815. }
  816.  
  817. //----------------------------------------------------------------------------------------
  818. //    FW_PrivString_ToLower
  819. //----------------------------------------------------------------------------------------
  820.  
  821. FW_HString FW_PrivString_ToLower(FW_HString self, FW_PlatformError* error)
  822. {
  823.     FW_HString rep = ::StringRep_Clone(self, error);
  824.     if (*error)
  825.         return 0;
  826. #ifdef FW_BUILD_MAC
  827.     ::LowercaseText(rep->fParams.fTextStart, 
  828.                     rep->fParams.fTextByteLength, 
  829.                     rep->fParams.fTextLocale.fScriptCode);
  830.     *error = ::ResError();
  831.     if (*error)
  832.         return 0;
  833. #elif defined FW_BUILD_WIN
  834.     //??? Need an international implementation for windows
  835.     for (int i=0; i<rep->fParams.fTextByteLength; i++)
  836.         rep->fParams.fTextStart[i] = tolower(rep->fParams.fTextStart[i]);
  837. #endif
  838.     return rep;
  839. }
  840.  
  841. //----------------------------------------------------------------------------------------
  842. //    RabinKarpSearch
  843. //
  844. // Reference: Introduction to Algorithms, By Corment, Leiserson & Rivest, page 860
  845. // Note: The standard library function strstr is possibly as efficient as RabinKarpSearch,
  846. // but unfortunately it assumes that both strings are NUL terminated ISO strings.  ODIText
  847. // data structures are not necessarily NUL terminated, so we can't use strstr.  Note also
  848. // that there are algorithms more efficient than Rabin-Karp, but they're more complicated
  849. // to implement, and unlikely to be significantly better than Rabin-Karp for most common
  850. // string searching tasks.  Developers creating text engines will probably keep their text
  851. // in some other kind of data structure and will have their own searching functions.
  852. //----------------------------------------------------------------------------------------
  853.  
  854. static unsigned long RadixPower(unsigned long radix, 
  855.                                 unsigned long power, 
  856.                                 unsigned long modulus)
  857. {
  858.     unsigned long result = 1;
  859.     while (--power > 0)
  860.         result = (result * radix) % modulus;
  861.     return result;
  862. }
  863.  
  864. class CPrivCharIterator
  865. {
  866. public:
  867.     CPrivCharIterator() {}
  868.     CPrivCharIterator(const unsigned char* pos, int delta) : fPos(pos), fDelta(delta) {}
  869.     CPrivCharIterator(const CPrivCharIterator& other) : fPos(other.fPos), fDelta(other.fDelta) {}
  870.     void operator++() { fPos += fDelta; }
  871.     operator const unsigned char*() const { return fPos; }
  872.     int operator==(const CPrivCharIterator& other) const { return fPos==other.fPos; }
  873.     int operator!=(const CPrivCharIterator& other) const { return fPos!=other.fPos; }
  874.     void operator=(const CPrivCharIterator& other) { fPos=other.fPos; fDelta=other.fDelta; }
  875.     unsigned char operator*() const { return *fPos; }
  876.     
  877. private:
  878.     const unsigned char* fPos;
  879.     int fDelta;
  880. };
  881.  
  882. const unsigned long kRadix = 256;
  883. const unsigned long kModulus = (1L<<24) - 3;    // this is the largest prime less than 2**24
  884.  
  885. static unsigned long RunValue(CPrivCharIterator& begin, CPrivCharIterator& limit)
  886. {
  887.     unsigned long value = 0;
  888.     CPrivCharIterator i;
  889.     for (i=begin; i!=limit; ++i)
  890.     {
  891.         unsigned char c = *i;
  892.         value = (kRadix*value + c) % kModulus;
  893.     }
  894.     return value;
  895. }
  896.  
  897. static int PrivCompare(const CPrivCharIterator& pat, 
  898.                         const CPrivCharIterator& window, 
  899.                         const CPrivCharIterator& patLimit)
  900. {
  901.     CPrivCharIterator i=pat;
  902.     CPrivCharIterator w=window;
  903.     
  904.     while (i!=patLimit)
  905.     {
  906.         if (*i != *w)
  907.             return 0;
  908.         ++i;
  909.         ++w;
  910.     }
  911.     return 1;
  912. }
  913.  
  914. static long RabinKarpSearch(const unsigned char* text, 
  915.                             const unsigned char* pat, 
  916.                             long n, // length of text
  917.                             long m,    // length of pat
  918.                             int searchForwards = 1)
  919. {
  920.     long shift = -1;
  921.     if (m <= 0)
  922.         return shift;
  923.     if (m > n)
  924.         return shift;
  925.     
  926.     const unsigned long h = RadixPower(kRadix, m, kModulus);
  927.  
  928.     CPrivCharIterator wbegin;
  929.     CPrivCharIterator wend;
  930.     CPrivCharIterator wlimit;
  931.     CPrivCharIterator pbegin;
  932.     CPrivCharIterator pend;
  933.  
  934.     if (searchForwards)
  935.     {
  936.         wbegin = CPrivCharIterator(text, 1);
  937.         wend = CPrivCharIterator(text+m, 1);
  938.         wlimit = CPrivCharIterator(text+n-m+1, 0);
  939.         pbegin = CPrivCharIterator(pat, 1);
  940.         pend = CPrivCharIterator(pat+m, 1);
  941.     }
  942.     else
  943.     {
  944.         wbegin = CPrivCharIterator(text+n-1, -1);
  945.         wend = CPrivCharIterator(text+n-m-1, -1);
  946.         wlimit = CPrivCharIterator(text-1, 0);
  947.         pbegin = CPrivCharIterator(pat+m-1, -1);
  948.         pend = CPrivCharIterator(pat-1, -1);
  949.     }
  950.  
  951.     unsigned long p = RunValue(pbegin, pend);
  952.     unsigned long t = RunValue(wbegin, wend);
  953.  
  954.     while (wbegin != wlimit)
  955.     {
  956.         if ((p == t) && PrivCompare(pbegin, wbegin, pend))
  957.         {
  958.             shift = (const unsigned char*)wbegin - text;
  959.             break;
  960.         }
  961.  
  962.         unsigned char c = *wbegin;
  963.         ++wbegin;
  964.  
  965.         if (wbegin != wlimit)
  966.         {
  967.             // subtract out the oldest character
  968.             unsigned long z = (c*h) % kModulus;
  969.             if (t >= z)
  970.                 t -= z;
  971.             else
  972.                 t = t + kModulus - z;
  973.  
  974.             // add in the new character
  975.             c = *wend;
  976.             t = (kRadix*t + c) % kModulus;
  977.  
  978.             ++wend;
  979.             FW_ASSERT(t == RunValue(wbegin, wend));
  980.         }
  981.         
  982.     }
  983.     
  984.     if (shift != -1 && !searchForwards)
  985.     {
  986.         shift -= (m-1);
  987.     }
  988.     
  989.     return shift;
  990. }
  991.  
  992. //----------------------------------------------------------------------------------------
  993. //    FW_PrivString_FindCharacter
  994. //----------------------------------------------------------------------------------------
  995.  
  996. static Boolean PrivIsCharacterMatch(FW_HString self, 
  997.                                 FW_ByteCount i,
  998.                                 FW_ByteCount *foundPosition)
  999. {
  1000.     Boolean result = false;
  1001.     FW_PlatformError error = 0;
  1002.     if (::FW_LocaleIsSingleByte(self->fParams.fTextLocale)
  1003.         || FW_TextParams_IsCharacterStart(&self->fText, 0, i, &error))
  1004.     {
  1005.         FW_ASSERT(error == 0);
  1006.         result = true;
  1007.         *foundPosition = i;
  1008.     }
  1009.     return result;
  1010. }
  1011.  
  1012. const FW_LChar kLowByteMask = 0x0FF;
  1013. const FW_LChar kLowByteAntiMask = ~kLowByteMask;
  1014.  
  1015. static void LCharToBytes(FW_LChar c, char* bytes)
  1016. {
  1017.     *bytes++ = c >> 8;
  1018.     *bytes = c & kLowByteMask;
  1019. }
  1020.  
  1021. FW_Boolean FW_PrivString_FindCharacter(FW_HString self, 
  1022.                         FW_LChar character, 
  1023.                         FW_ByteCount *foundPosition, 
  1024.                         FW_ByteCount startPosition,
  1025.                         FW_FindDirection direction)
  1026. {
  1027.     FW_Boolean result = false;    // assume failure to find character
  1028.     
  1029.     if ((character & kLowByteAntiMask) == 0)
  1030.     {
  1031.         // If the character we're searching for is a single byte character
  1032.         // then we can use a simple char-by-char scan
  1033.         register char c = (char) (character & kLowByteMask);
  1034.         register const char* text = self->fParams.fTextStart;
  1035.         if (direction == FW_kForwards)
  1036.         {
  1037.             for (FW_ByteCount i=startPosition; i<self->fParams.fTextByteLength; i++)
  1038.             {
  1039.                 if ((text[i] == c) && (result=PrivIsCharacterMatch(self, i, foundPosition)) == true)
  1040.                     break;
  1041.             }
  1042.         }
  1043.         else
  1044.         {
  1045.             for (FW_ByteCount i=startPosition; i>=0; i--)
  1046.             {
  1047.                 if ((text[i] == c) && (result=PrivIsCharacterMatch(self, i, foundPosition)) == true)
  1048.                     break;
  1049.             }
  1050.         }
  1051.     }
  1052.     else if (!::FW_LocaleIsSingleByte(self->fParams.fTextLocale))
  1053.     {
  1054.         // If we've gotten to here, we have a locale that is not single-byte,
  1055.         // and we're searching for a character that is not a single-byte character.
  1056.         // We handle that case by making a single-character string and then doing
  1057.         // a substring search.
  1058.         char bytes[2];
  1059.         LCharToBytes(character, bytes);
  1060.         *foundPosition = RabinKarpSearch((const unsigned char*)self->fParams.fTextStart+startPosition, 
  1061.                             (const unsigned char*)bytes, 
  1062.                             self->fParams.fTextByteLength-startPosition,
  1063.                             2,    // length of pat
  1064.                             direction == FW_kForwards);
  1065.         result = *foundPosition != -1;
  1066.         if (result)
  1067.         {
  1068.             *foundPosition += startPosition;
  1069.         }
  1070.     }
  1071.     else
  1072.     {
  1073.         // If we've gotten to here, we're trying to find a multi-byte character
  1074.         // in a single-byte locale string. By definition, that must fail, right?
  1075.         // Since result is already set to false, we don't have to do anything.
  1076.     }
  1077.     return result;
  1078. }
  1079.  
  1080. //----------------------------------------------------------------------------------------
  1081. //    FW_PrivString_FindSubString
  1082. //----------------------------------------------------------------------------------------
  1083.  
  1084. FW_Boolean FW_PrivString_FindSubString(FW_HString self, 
  1085.                         FW_HString subString, 
  1086.                         FW_ByteCount *foundPosition, 
  1087.                         FW_ByteCount startPosition)
  1088. {
  1089.     *foundPosition = RabinKarpSearch((const unsigned char*) self->fParams.fTextStart+startPosition,
  1090.                                 (const unsigned char*) subString->fParams.fTextStart,
  1091.                                 self->fParams.fTextByteLength-startPosition,
  1092.                                 subString->fParams.fTextByteLength);
  1093.     if (*foundPosition != -1)
  1094.         *foundPosition += startPosition;
  1095.     return (*foundPosition != -1);
  1096. }
  1097.  
  1098. //----------------------------------------------------------------------------------------
  1099. //    FW_PrivString_Substitute
  1100. //----------------------------------------------------------------------------------------
  1101.  
  1102. FW_HString FW_PrivString_Substitute(FW_HString self, 
  1103.                         FW_HString searchString, 
  1104.                         FW_HString substitutionString, 
  1105.                         FW_Boolean* wasReplaced, 
  1106.                         FW_PlatformError* error)
  1107. {
  1108.     FW_HString rep = self;
  1109.     FW_ByteCount foundPosition;
  1110.     *wasReplaced = false;
  1111.     if (::FW_PrivString_FindSubString(self, searchString, &foundPosition, 0))
  1112.     {
  1113.         FW_HString temp;
  1114.         rep = ::StringRep_Clone(self, error);
  1115.         temp = ::FW_PrivString_Delete(rep, 
  1116.                                     FW_PrivString_GetByteLength(searchString), 
  1117.                                     foundPosition,
  1118.                                     error);
  1119.         if (*error)
  1120.             return 0;
  1121.         FW_PRIV_ASSERT(temp == rep);
  1122.         temp = ::FW_PrivString_InsertStringRep(rep, 
  1123.                                         substitutionString, 
  1124.                                         foundPosition, 
  1125.                                         error);
  1126.         if (*error)
  1127.             return 0;
  1128.         FW_PRIV_ASSERT(temp == rep);
  1129.         *wasReplaced = true;
  1130.     }
  1131.     return rep;
  1132. }
  1133.  
  1134. //----------------------------------------------------------------------------------------
  1135. //    FW_WinHackTextCompare
  1136. //----------------------------------------------------------------------------------------
  1137.  
  1138. #ifdef FW_BUILD_WIN
  1139. // This is a hack.  It does a byte level compare.
  1140. // We need the proper text compare routine for windows
  1141. static FW_StringCompareResult FW_WinHackTextCompare(
  1142.                         const char *p1, 
  1143.                         const char *p2,
  1144.                         FW_ByteCount len1,
  1145.                         FW_ByteCount len2)
  1146. {
  1147.     FW_ByteCount len = len1;
  1148.     int result = 0;     // assume strings are equal
  1149.     if (len1 < len2)
  1150.         result = -1;    // now assume string 1 is less because it's shorter
  1151.     else if (len1 > len2)
  1152.     {
  1153.         result = 1;        // now assume string 1 is greater because it's longer
  1154.         len = len2;
  1155.     }
  1156.     
  1157.     const unsigned char* s1 = (const unsigned char*) p1;
  1158.     const unsigned char* s2 = (const unsigned char*) p2;
  1159.     
  1160.     unsigned char c1 = *s1;
  1161.     unsigned char c2 = *s2;
  1162.  
  1163.     while (len-- > 0)
  1164.     {
  1165.         c1 = *s1++;
  1166.         c2 = *s2++;
  1167.         if (!c1)
  1168.             break;
  1169.         if (c1 != c2)
  1170.             break;
  1171.     }
  1172.     
  1173.     if (len > 0)
  1174.     {
  1175.         if (c1 < c2)
  1176.             result = -1;
  1177.         if (c1 > c2)
  1178.             result = 1;
  1179.     }
  1180.         
  1181.     return result;
  1182. }
  1183. #endif
  1184.  
  1185. //----------------------------------------------------------------------------------------
  1186. //    FW_PrivString_Compare
  1187. //----------------------------------------------------------------------------------------
  1188.  
  1189. FW_StringCompareResult FW_PrivString_Compare(FW_HString string1, FW_HString string2)
  1190. {
  1191. #ifdef FW_BUILD_MAC
  1192.     return ::TextOrder(string1->fParams.fTextStart, 
  1193.                          string2->fParams.fTextStart, 
  1194.                          string1->fParams.fTextByteLength, 
  1195.                          string2->fParams.fTextByteLength, 
  1196.                          string1->fParams.fTextLocale.fScriptCode, 
  1197.                          string2->fParams.fTextLocale.fScriptCode, 
  1198.                          string1->fParams.fTextLocale.fLangCode, 
  1199.                          string2->fParams.fTextLocale.fLangCode);
  1200. #else
  1201.     return ::FW_WinHackTextCompare(string1->fParams.fTextStart, 
  1202.                          string2->fParams.fTextStart, 
  1203.                          string1->fParams.fTextByteLength, 
  1204.                          string2->fParams.fTextByteLength);
  1205. #endif
  1206. }
  1207.  
  1208. //----------------------------------------------------------------------------------------
  1209. //    Number Conversion Functions
  1210. //----------------------------------------------------------------------------------------
  1211.  
  1212. //----------------------------------------------------------------------------------------
  1213. //    FW_PrivString_SignedIntegerToDecimalString
  1214. //----------------------------------------------------------------------------------------
  1215.  
  1216. FW_HString FW_PrivString_SignedIntegerToDecimalString(FW_HString self, 
  1217.                                                     long integer, 
  1218.                                                     FW_PlatformError* error)
  1219. {
  1220.     // we allow for the possiblity that longs are more than 32 bits
  1221.     const int kMaxDigits = 32;
  1222.     char string[kMaxDigits];
  1223.     FW_Boolean negative = integer < 0;
  1224.     if (negative) 
  1225.         integer = -integer;
  1226.     const char kZero = '0';
  1227.     const long int kBase = 10;
  1228.         
  1229.     int i = kMaxDigits;
  1230.  
  1231.     if (integer == 0)
  1232.     {
  1233.         --i;
  1234.         string[i] = kZero;
  1235.     }
  1236.     else
  1237.     {
  1238.         while (integer > 0)
  1239.         {
  1240.             --i;
  1241.             string[i] = (char) (integer % kBase) + kZero;
  1242.             integer = integer / kBase;
  1243.         }
  1244.     }
  1245.     
  1246.     if (negative)
  1247.     {
  1248.         --i;
  1249.         string[i] = '-';
  1250.     }
  1251.     
  1252.     return ::FW_PrivString_ReplaceAllBytes(self, string+i, kMaxDigits-i, error);
  1253. }
  1254.  
  1255. //----------------------------------------------------------------------------------------
  1256. //    FW_PrivString_UnsignedIntegerToDecimalString
  1257. //----------------------------------------------------------------------------------------
  1258.  
  1259. FW_HString FW_PrivString_UnsignedIntegerToDecimalString(FW_HString self, 
  1260.                                                     unsigned long integer, 
  1261.                                                     FW_PlatformError* error)
  1262. {
  1263.     // we allow for the possiblity that longs are more than 32 bits
  1264.     const int kMaxDigits = 32;
  1265.     char string[kMaxDigits];
  1266.     const char kZero = '0';
  1267.     const long int kBase = 10;
  1268.         
  1269.     int i = kMaxDigits;
  1270.  
  1271.     if (integer == 0)
  1272.     {
  1273.         --i;
  1274.         string[i] = kZero;
  1275.     }
  1276.     else
  1277.     {
  1278.         while (integer > 0)
  1279.         {
  1280.             --i;
  1281.             string[i] = (char) (integer % kBase) + kZero;
  1282.             integer = integer / kBase;
  1283.         }
  1284.     }
  1285.     
  1286.     return ::FW_PrivString_ReplaceAllBytes(self, string+i, kMaxDigits-i, error);
  1287. }
  1288.  
  1289. //----------------------------------------------------------------------------------------
  1290. //    FW_PrivString_UnsignedIntegerToHexadecimalString
  1291. //----------------------------------------------------------------------------------------
  1292.  
  1293. FW_HString FW_PrivString_UnsignedIntegerToHexadecimalString(FW_HString self, 
  1294.                                                     unsigned long integer, 
  1295.                                                     FW_PlatformError* error)
  1296. {
  1297.     // we allow for the possiblity that longs are more than 32 bits
  1298.     const int kMaxDigits = 32;
  1299.     char string[kMaxDigits];
  1300.     const char kZero = '0';
  1301.     const char kA = 'A';
  1302.     const long int kBase = 16;
  1303.         
  1304.     int i = kMaxDigits;
  1305.  
  1306.     if (integer == 0)
  1307.     {
  1308.         --i;
  1309.         string[i] = kZero;
  1310.     }
  1311.     else
  1312.     {
  1313.         while (integer > 0)
  1314.         {
  1315.             --i;
  1316.             unsigned long digit = (integer % kBase);
  1317.             if (digit < 10)
  1318.                 string[i] = (char) digit + kZero;
  1319.             else
  1320.                 string[i] = (char) digit + kA;
  1321.             integer = integer / kBase;
  1322.         }
  1323.     }
  1324.     
  1325.     return ::FW_PrivString_ReplaceAllBytes(self, string+i, kMaxDigits-i, error);
  1326. }
  1327.  
  1328. //----------------------------------------------------------------------------------------
  1329. //    FW_PrivString_DecimalStringToSignedInteger
  1330. //----------------------------------------------------------------------------------------
  1331.  
  1332. long FW_PrivString_DecimalStringToSignedInteger(FW_HString self)
  1333. {
  1334.     const char* string = self->fParams.fTextStart;
  1335.     const char* last = string + self->fParams.fTextByteLength;
  1336.     FW_Boolean negative = (*string == '-');
  1337.     const char kZero = '0';
  1338.     const char kNine = '9';
  1339.     const long int kBase = 10;
  1340.     long result = 0;
  1341.  
  1342.     if (negative)
  1343.         ++string;
  1344.     
  1345.     while ((string<last) && (*string >= kZero) && (*string <= kNine))
  1346.     {
  1347.         long digit = *string - kZero;
  1348.         result = result*kBase + digit;
  1349.         ++string;
  1350.     }
  1351.     
  1352.     if (negative)
  1353.         result = -result;
  1354.     
  1355.     return result;
  1356. }
  1357.  
  1358. //----------------------------------------------------------------------------------------
  1359. //    FW_PrivString_DecimalStringToUnsignedInteger
  1360. //----------------------------------------------------------------------------------------
  1361.  
  1362. unsigned long FW_PrivString_DecimalStringToUnsignedInteger(FW_HString self)
  1363. {
  1364.     const char* string = self->fParams.fTextStart;
  1365.     const char* last = string + self->fParams.fTextByteLength;
  1366.     const char kZero = '0';
  1367.     const char kNine = '9';
  1368.     const unsigned long int kBase = 10;
  1369.     unsigned long result = 0;
  1370.  
  1371.     while ((string<last) && (*string >= kZero) && (*string <= kNine))
  1372.     {
  1373.         unsigned long digit = *string - kZero;
  1374.         result = result*kBase + digit;
  1375.         ++string;
  1376.     }
  1377.     
  1378.     return result;
  1379. }
  1380.  
  1381. //----------------------------------------------------------------------------------------
  1382. //    IsHex
  1383. //----------------------------------------------------------------------------------------
  1384.  
  1385. static FW_Boolean IsHex(const char hexChar, unsigned long& digit)
  1386. {
  1387.     FW_Boolean result = false;
  1388.     if (hexChar>='0' && hexChar<='9')
  1389.     {
  1390.         result = true;
  1391.         digit = hexChar - '0';
  1392.     }
  1393.     else if (hexChar>='a' && hexChar<='f')
  1394.     {
  1395.         result = true;
  1396.         digit = hexChar - 'a';
  1397.     }
  1398.     else if (hexChar>='A' && hexChar<='F')
  1399.     {
  1400.         result = true;
  1401.         digit = hexChar - 'A';
  1402.     }
  1403.     return result;
  1404. }
  1405.  
  1406. //----------------------------------------------------------------------------------------
  1407. //    FW_PrivString_HexadecimalStringToUnsignedInteger
  1408. //----------------------------------------------------------------------------------------
  1409.  
  1410. unsigned long FW_PrivString_HexadecimalStringToUnsignedInteger(FW_HString self)
  1411. {
  1412.     const char* string = self->fParams.fTextStart;
  1413.     const char* last = string + self->fParams.fTextByteLength;
  1414.     const unsigned long int kBase = 16;
  1415.     unsigned long result = 0;
  1416.     unsigned long digit;
  1417.  
  1418.     while ((string<last) && IsHex(*string, digit))
  1419.     {
  1420.         result = result*kBase + digit;
  1421.         ++string;
  1422.     }
  1423.     
  1424.     return result;
  1425. }
  1426.  
  1427. //----------------------------------------------------------------------------------------
  1428. //    FW_PrivString_DoubleToString
  1429. //----------------------------------------------------------------------------------------
  1430.  
  1431. FW_HString FW_PrivString_DoubleToString(FW_HString self, 
  1432.                                         double value, 
  1433.                                         short fractionalDigits, 
  1434.                                         FW_PlatformError* error)
  1435. {
  1436. #ifdef FW_BUILD_MAC
  1437.     decform form = {FIXEDDECIMAL, 0, fractionalDigits};
  1438.     decimal intermediate;
  1439.     char buffer[DECSTROUTLEN];
  1440.     
  1441.     num2dec(&form, value, &intermediate);
  1442.     dec2str(&form, &intermediate, buffer);
  1443.     
  1444.     return ::FW_PrivString_ReplaceAllBytes(self, 
  1445.                                         buffer, 
  1446.                                         FW_PrimitiveStringLength(buffer), 
  1447.                                         error);
  1448. #elif defined FW_BUILD_WIN
  1449.     FW_PRIV_ASSERT(Not_Yet_Implemented);
  1450.     return (FW_HString) NULL;
  1451. #endif
  1452. }
  1453.  
  1454. //----------------------------------------------------------------------------------------
  1455. //    FW_PrivString_DoubleToString
  1456. //----------------------------------------------------------------------------------------
  1457. #include <stdio.h>
  1458. double FW_PrivString_StringToDouble(FW_HString self)
  1459. {
  1460.     double result = 0;
  1461.     
  1462. #if 1
  1463.     char buffer[256];
  1464.     FW_PrivString_ExportCString(self, buffer);
  1465.     sscanf(buffer, "%lg", &result);
  1466. #elif defined FW_BUILD_MAC
  1467.     // The following doesn't work, and I don't know why. -JEL
  1468.     decimal intermediate;
  1469.     short ix, vp;    // I don't know what these are for!!!
  1470.     char buffer[256];
  1471.     FW_PrivString_ExportCString(self, buffer);
  1472.     
  1473.     str2dec(buffer, &ix, &intermediate, &vp);    // intermediate ends up with garbage
  1474.     result = dec2num(&intermediate);
  1475. #elif defined FW_BUILD_WIN
  1476.     FW_PRIV_ASSERT(Not_Yet_Implemented);
  1477. #endif
  1478.  
  1479.     return result;
  1480. }
  1481.